/**
 * chinagoods.com
 * Copyright (c) 2020-2024 All Rights Reserved.
 */
package com.ruoyi.web.controller.api;
/**
 * @author yangpeng
 * Created by on 2024-01-22 21:27
 */

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.ResponseResult;
import com.ruoyi.common.enums.ChannelEnum;
import com.ruoyi.common.utils.sign.SignMD5Util;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.system.biz.CashBizService;
import com.ruoyi.system.biz.CashHistoryBizService;
import com.ruoyi.system.biz.MerchantCountBizService;
import com.ruoyi.system.biz.UserCountBizService;
import com.ruoyi.system.domain.Order;
import com.ruoyi.system.domain.UserRate;
import com.ruoyi.system.dto.ApiOrderReceiveAddDto;
import com.ruoyi.system.service.CashHistoryService;
import com.ruoyi.system.service.OrderService;
import com.ruoyi.system.service.UserRateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Api(tags = "开放接口---测试并发")
@RestController
@RequestMapping("/api/orderPay")
@Slf4j
public class BFController {


    @Resource
    private UserRateService userRateService;


    @Resource
    private CashHistoryService cashHistoryService;
    @Resource
    private UserCountBizService userCountBizService;
    @Resource
    private OrderService orderService;
    @Resource
    private MerchantCountBizService merchantCountBizService;
    @Resource
    private CashHistoryBizService cashHistoryBizService;
    // 请求总数
    public static int clientTotal = 1000;

    // 同时并发执行的线程总数
    public static int threadTotal = 200;

    public static int count = 0;


    @ApiOperation(value = "初始话小额uid")
    @GetMapping("/initUid")
    public ResponseResult initUid() {
        UserRate userRate = new UserRate();
        userRate.setChannelCode(ChannelEnum.UID.getCode());
        PageDomain pageDomain = new PageDomain();
        pageDomain.setPageSize(1000);
        List<UserRate> list = userRateService.findList(userRate, pageDomain);
        List<UserRate> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            UserRate userRate1 = list.get(i);
            UserRate domain = new UserRate();
            domain.setChannelCode(ChannelEnum.SM_UID.getCode());
            domain.setChannelCode(ChannelEnum.SM_UID.getName());
            domain.setUserId(userRate1.getUserId());
            domain.setRate(userRate1.getRate());
            domain.setUsername(userRate1.getUsername());
            result.add(domain);
        }
        if (CollectionUtil.isNotEmpty(result)) {
            userRateService.addDomainBatch(result);
        }
        return ResponseResult.createBySuccess();
    }

    @ApiOperation(value = "addUserCount")
    @GetMapping("/addUserCount")
    public ResponseResult addUserCount() throws InterruptedException {

        userCountBizService.addUserCountForMonth();

        return ResponseResult.createBySuccess();

    }

    @ApiOperation(value = "addMerchantCount")
    @GetMapping("/addMerchantCount")
    public ResponseResult addMerchantCount() throws InterruptedException {
        merchantCountBizService.addUserCountForMonth();
        return ResponseResult.createBySuccess();
    }

    @ApiOperation(value = "checkError")
    @GetMapping("/checkError")
    public ResponseResult checkError() throws InterruptedException {
        Date start = DateUtil.beginOfDay(new Date());
        cashHistoryBizService.checkError(start, new Date());

        return ResponseResult.createBySuccess();

    }


    @ApiOperation(value = "增加余额--优化")
    @GetMapping("/addCash1")
    public ResponseResult addCash1() {
        int threadCount = 100; // 假设我们想要并发运行10个线程
        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++) {
            threads[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 5; j++) {
//                        Long userId = 1L;
//                        String changeType = "add";
//                        CashHistory userCashHis = new CashHistory(userId, new BigDecimal(1), changeType, "测试并发", "sysUpdate");
//                        userCashHis.setSource("admin");
//                        cashService.updateCash(userCashHis);
                        ApiOrderReceiveAddDto apiOrderReceiveAddDto = new ApiOrderReceiveAddDto();
                        apiOrderReceiveAddDto.setMerchantId(1L);
                        apiOrderReceiveAddDto.setChannelCode("10007");
                        apiOrderReceiveAddDto.setPayer("哈哈");
                        apiOrderReceiveAddDto.setAmount(new BigDecimal(100));
                        apiOrderReceiveAddDto.setNotifyUrl("www");
                        String orderNo = System.currentTimeMillis() + "" + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10);
                        apiOrderReceiveAddDto.setMerchantOrderNo(orderNo);
                        String serSign = SignMD5Util.getSerSign(apiOrderReceiveAddDto, "123456");

                        apiOrderReceiveAddDto.setSign(serSign);
                        orderService.apiOrder(apiOrderReceiveAddDto, "sys");
                    }
                }
            });
            threads[i].start();
        }

        // 等待所有线程完成
        for (int i = 0; i < threadCount; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


        return ResponseResult.createBySuccess();
    }

    @ApiOperation(value = "并发下单")
    @GetMapping("/testBf")
    public ResponseResult testBf1() throws InterruptedException {
        testBf();
        return ResponseResult.createBySuccess();
    }

    private static final int B = 500; // 假设我们要测试1000个并发用户
    private static final int N = 20; // 每个并发用户执行10000次操作

    public void testBf() throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(B);

        CountDownLatch startGate = new CountDownLatch(1);
        CountDownLatch endGate = new CountDownLatch(B);

        for (int i = 0; i < B; i++) {
            executor.execute(() -> {
                try {
                    // 等待所有线程都准备好后再开始计数
                    startGate.await();

                    for (int j = 0; j < N; j++) {
                        // 这里放置并发执行的代码
                        // 例如: 数据库操作，网络请求等
                        ApiOrderReceiveAddDto apiOrderReceiveAddDto = new ApiOrderReceiveAddDto();
                        apiOrderReceiveAddDto.setMerchantId(1L);
                        apiOrderReceiveAddDto.setChannelCode("10004");
                        apiOrderReceiveAddDto.setPayer("哈哈");
                        apiOrderReceiveAddDto.setAmount(new BigDecimal(10));
                        apiOrderReceiveAddDto.setNotifyUrl("http://127.0.0.1:8088/api/order/notifyMe");
                        String orderNo = (int) (Math.random() * 10) + (int) (Math.random() * 10) + UUID.fastUUID().toString() + "" + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10) + (int) (Math.random() * 10);
                        apiOrderReceiveAddDto.setMerchantOrderNo(orderNo);
                        String serSign = SignMD5Util.getSerSign(apiOrderReceiveAddDto, "123456");

                        apiOrderReceiveAddDto.setSign(serSign);
                        orderService.apiOrder(apiOrderReceiveAddDto, "sys");

                    }
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                } finally {
                    endGate.countDown(); // 每个线程执行完后释放一个countDown
                }
            });
        }

        long start = System.nanoTime();
        startGate.countDown(); // 开始并发执行
        endGate.await(); // 等待所有并发执行结束
        long end = System.nanoTime();
        executor.shutdown();

    }

    @ApiOperation(value = "并发确认订单")
    @GetMapping("/testFinish1")
    public ResponseResult testFinish1() throws InterruptedException {
        testFinish();
        return ResponseResult.createBySuccess();
    }

    private static final int B1 = 4; // 假设我们要测试1000个并发用户
    private static final int N1 = 50; // 每个并发用户执行10000次操作
    @Resource
    private RedissonClient redissonClient;

    public void testFinish() throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(B);

        CountDownLatch startGate = new CountDownLatch(1);
        CountDownLatch endGate = new CountDownLatch(B);

        for (int i = 0; i < B1; i++) {
            int finalI = i;
            executor.execute(() -> {
                try {
                    // 等待所有线程都准备好后再开始计数
                    startGate.await();

                    for (int j = 0; j < N1; j++) {
                        // 这里放置并发执行的代码
                        // 例如: 数据库操作，网络请求等
                        //确认订单

                        Long id = (long) (finalI * 50 + (j + 1));
                        Order order = orderService.getById(id);
                        if (order == null) {
                            continue;
                        }
                        RLock lock = redissonClient.getLock(CacheConstants.UPDATE_ORDER + id);
                        //        再锁用户

                        try {
                            lock.lock(CacheConstants.LOCK_TIME, TimeUnit.SECONDS);

                            orderService.finish(id);
                            Long id1 = (long) (finalI * 200 + (j + 1));
                            order = orderService.getById(id);
                            if (order == null) {
                                continue;
                            }
                            orderService.release(id1);
                        } finally {

                            lock.unlock();
                        }


                    }
                } catch (Exception e) {
                    // Thread.currentThread().interrupt();
                } finally {
                    endGate.countDown(); // 每个线程执行完后释放一个countDown
                }
            });
        }

        long start = System.nanoTime();
        startGate.countDown(); // 开始并发执行
        endGate.await(); // 等待所有并发执行结束
        long end = System.nanoTime();
        executor.shutdown();

    }


}
